package com.cvai.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cvai.R.PageResult;
import com.cvai.context.BaseContext;
import com.cvai.domain.dto.ChatDto;
import com.cvai.domain.dto.LoginDto;
import com.cvai.domain.po.Auth;
import com.cvai.domain.po.Chat;
import com.cvai.domain.po.Memory;
import com.cvai.domain.po.User;
import com.cvai.domain.vo.UserVo;
import com.cvai.mapper.ChatMapper;
import com.cvai.mapper.MemoryMapper;
import com.cvai.mapper.UserMapper;
import com.cvai.properties.JwtProperties;
import com.cvai.service.IUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cvai.util.JwtUtil;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.model.AuthResponse;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author cv
 * @since 2025-03-09
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    private final JwtProperties jwtProperties;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    private final ChatMapper chatMapper;
    private final MemoryMapper memoryMapper;

    @Override
    @Transactional
    public UserVo login(LoginDto loginDto) {
        if (loginDto == null)
            throw new RuntimeException("参数错误");
        if (loginDto.getUsername() == null)
            throw new RuntimeException("用户名不能为空");
        if (loginDto.getPassword() == null)
            throw new RuntimeException("密码不能为空");
        LambdaQueryWrapper<User> qw = new LambdaQueryWrapper<>();
        qw.eq(User::getUsername, loginDto.getUsername());
        User user = getOne(qw);
        if (user == null)
            throw new RuntimeException("用户名不存在");
        if (!user.getPassword().equals(loginDto.getPassword()))
            throw new RuntimeException("密码错误");

        user.setLastLoginTime(LocalDateTime.now());
        updateById(user);
        Set<String> keys = redisTemplate.keys("*_" + user.getId());
        if (keys != null && !keys.isEmpty()) {
            redisTemplate.delete(keys);
        }
        return getUserVo(loginDto, user);
    }


    @Override
    @Transactional
    public UserVo register(LoginDto loginDto) {
        if (loginDto == null)
            throw new RuntimeException("参数错误");
        if (loginDto.getUsername() == null)
            throw new RuntimeException("用户名不能为空");
        if (loginDto.getPassword() == null)
            throw new RuntimeException("密码不能为空");
        if (loginDto.getRePassword() == null)
            throw new RuntimeException("重复密码不能为空");
        if (!loginDto.getPassword().equals(loginDto.getRePassword()))
            throw new RuntimeException("两次密码不一致");
        if (getOne(new LambdaQueryWrapper<User>().eq(User::getUsername, loginDto.getUsername())) != null)
            throw new RuntimeException("用户名已存在");
        User user = new User();
        BeanUtils.copyProperties(loginDto, user);
        user.setDeliveryType(0);
        user.setCreateTime(LocalDateTime.now());
        user.setLastLoginTime(LocalDateTime.now());
        save(user);

        return getUserVo(loginDto, user);
    }

    @Override
    public PageResult getChatList(Integer pageNum) {
        if (pageNum == null) {
            pageNum = 1;
        }
        Page<Memory> memoryPage = new Page<>(pageNum, 10);

        // 使用 LambdaQueryWrapper 构建查询条件，并指定正确的表和字段
        LambdaQueryWrapper<Memory> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Memory::getUserId, BaseContext.getCurrentUser().getId())
                .isNotNull(Memory::getName);

        memoryPage = memoryMapper.selectPage(memoryPage, queryWrapper);

        if (memoryPage.getRecords() != null) {
            PageResult pageResult = new PageResult();
            pageResult.setTotal(memoryPage.getTotal());
            pageResult.setPageNum((int) memoryPage.getCurrent());
            pageResult.setPageSize((int) memoryPage.getSize());
            pageResult.setRecords(memoryPage.getRecords());
            pageResult.setPages(memoryPage.getPages());
            return pageResult;
        }
        return null;
    }

    @Override
    public String render(AuthResponse response) {
        if(response.getCode()!=2000) {
            throw new RuntimeException("第三方登录失败");
        }

        Auth auth = JSON.parseObject(JSON.toJSONString(response.getData()), Auth.class);
        User user = new User();
        user.setId(Long.valueOf(auth.getUuid()));
        redisTemplate.delete("*_"+user.getId());
        user.setUsername("第三方登录用户："+auth.getNickname());
        user.setAvatar(auth.getAvatar());
        user.setCreateTime(LocalDateTime.now());
        user.setLastLoginTime(LocalDateTime.now());
        user.setDeliveryType(1);
        saveOrUpdate(user);
        UserVo userVo = getUserVo(null, user);
        String s = JSON.toJSONString(userVo);
        String code = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set(code, s, 5, TimeUnit.MINUTES);

        return code;
    }

    @Override
    public UserVo getUserVo(String code) {
        String s = redisTemplate.opsForValue().get(code);
        try {
            UserVo userVo = JSON.parseObject(s, UserVo.class);
            redisTemplate.delete(code);

            return userVo;
        } catch (Exception e) {
            throw new RuntimeException("验证码错误");
        }
    }

    @Override
    public void logout(HttpServletRequest request) {
        User user = BaseContext.getCurrentUser();
        BaseContext.removeCurrentUser();
        String token = request.getHeader(jwtProperties.getTokenName());
        log.info("当前用户token为：{}", token);
        Boolean delete = redisTemplate.delete(token + "_" + user.getId());
        log.info("当前用户为：{}", delete);
    }


    @NotNull
    private UserVo getUserVo(LoginDto loginDto, User user) {
        String s = JSON.toJSONString(user);
        Map<String, Object> claims = new HashMap<>();
        claims.put(jwtProperties.getTokenName(), s);
        String token = JwtUtil.createJWT(jwtProperties.getSecret(), jwtProperties.getExpire(), claims);
        UserVo userVo = new UserVo();
        BeanUtils.copyProperties(user, userVo);
        redisTemplate.opsForValue().set(token+"_"+user.getId(), s, jwtProperties.getExpire(), TimeUnit.MILLISECONDS);
        userVo.setToken(token);
        if(loginDto!=null){
            ChatDto chatDto = loginDto.getChatDto();

            log.info("chatDto:{}", chatDto);

            if (chatDto.getMemoryId().length()>0) {
                Chat chat = new Chat();
                Memory memory = new Memory();
                memory.setUserId(user.getId());
                memory.setId(chatDto.getMemoryId());
                memoryMapper.updateById(memory);
                BeanUtils.copyProperties(chatDto, chat);
                chat.setUserId(user.getId());
                log.info("插入chat：{}", chat);
                chatMapper.insert(chat);
            }
        }
        BaseContext.setCurrentUser(user);
        return userVo;
    }
}
